#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>

#include <common/macro/build.h>
#include <common/macro/debug.h>

/** 
* @brief Merge multiple strings into one. Takes variable number of arguments,
* last argument must be NULL.
* 
* @param base
* @param ...
* 
* @return Newly allocated string.
*/
API_LIBLOCAL char *util_strmerge(const char *base, ...) {
	char *in, *out;
	va_list ap;
	size_t len, offset;

	assert(base != NULL);

	len = strlen(base);
	out = malloc(len + 1);
	strcpy(out, base);
	offset = len;

	va_start(ap, base);
	while ((in = va_arg(ap, char*)) != NULL) {
		len += strlen(in);
		out = realloc(out, len + 1);
		strcpy(out + offset, in);
		offset = len;
	}
	va_end(ap);

	return out;
}

/** 
* @brief Returns minimum from length of the string the given maximum
* string length.
* 
* @param in
* @param size
* 
* @return 
*/
API_LIBLOCAL size_t util_strnlen(const char *in, size_t size) {
	size_t slen;

	assert(in != NULL);

	slen = 0;
	while (in[slen] != '\0') {
		if (slen >= size)
			break;
		slen++;
	}
	return slen;
}

/** 
* @brief Returns newly allocated string duplicate of the given maximum size.
* 
* @param in
* @param size
* 
* @return 
*/
API_LIBLOCAL char *util_sntrdup(const char *in, size_t size) {
	char *out;
	size_t slen;

	assert(in != NULL);

	/* First, figure out the length of the string. */
	slen = util_strnlen(in, size);

	if (slen == 0)
		return NULL;

	out = malloc(slen + 1);
	memcpy(out, in, slen);
	out[slen] = '\0';

	return out;
}

/** 
* @brief Creates a newly allocated area in memory, and fills it with data
* from the given source.
* 
* @param ptr
* @param size
* 
* @return 
*/
API_LIBLOCAL void *util_memdup(const void *ptr, const size_t size) {
	void *rv;

	assert(ptr != NULL);

	rv = malloc(size);
	memcpy(rv, ptr, size);
	return rv;
}
